﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Missbot.Common;
using Missbot.Core.Base;
using Missbot.Model.MsgInfos;
using Newtonsoft.Json;

namespace Missbot.Core
{
    /// <summary>
    /// 消息通道管理器
    /// </summary>
    public class ChannelMgr : ISingleton
    {
        /// <summary>
        /// 所有的消息通道
        /// </summary>
        public List<IMsgChannel> AllChannels { get; private set; }

        private Action<InboxSession> InboxCallback;

        public IMsgChannel this[string name] => AllChannels.FirstOrDefault(p => p.Name == name);

        /// <summary>
        /// 初始化消息通道管理器
        /// </summary>
        /// <param name="InboxCallback"></param>
        public void Init(Action<InboxSession> InboxCallback)
        {
            AllChannels = AutofacSvc.LoadAllInstanceFromClass<IMsgChannel>();
            this.InboxCallback = InboxCallback;
        }

        /// <summary>
        /// 消息接收事件
        /// </summary>
        /// <param name="msg"></param>
        public void OnMessageReceived(string msg)
        {
            var info = JsonConvert.DeserializeObject<ChannelInfo>(msg);
            // 先解析出通道的基础类型，然后再获取对应的通道实例
            var channelType = info?.Body.Type;
            if (string.IsNullOrEmpty(channelType))
            {
                return;
            }

            var channel = AllChannels.FirstOrDefault(p => p.ChannelFlag == channelType);
            var inbox = channel?.ParseData(msg);
            if (inbox == null)
            {
                return;
            }

            // 新开线程处理消息，防止阻塞
            Task.Factory.StartNew(() => InboxCallback?.Invoke(inbox));
        }

        /// <summary>
        /// 在特定的消息通道上注册等待服务
        /// </summary>
        /// <param name="channelName">消息通道名</param>
        /// <param name="judgeFunc">判断表达式</param>
        /// <param name="timeout">超时时间</param>
        /// <returns>捕获到的消息</returns>
        public InboxSession Wait(string channelName, Predicate<InboxSession> judgeFunc, int timeout = 10)
        {
            return this[channelName]?.Wait(judgeFunc, timeout);
        }

        public List<InboxSession> Wait(string channelName, List<Predicate<InboxSession>> judgeFuncGroup, int timeout = 10)
        {
            return this[channelName]?.Wait(judgeFuncGroup, timeout);
        }
    }
}